<?php
// +----------------------------------------------------------------------
// | Author: wyd 2025/8/26
// +----------------------------------------------------------------------

declare (strict_types=1);

namespace app\api\controller;


use app\api\exception\ApiException;
use app\api\model\Order;
use app\api\repository\WeChatMerchantRepository;
use app\service\WxService;
use think\facade\Log;
use think\facade\View;
use think\Request;

class Pay extends Base
{
    const WX = 'Wx';
    const ZFB = 'Zfb';

    /**
     * 获取支付方式
     */
    private function getPayType()
    {
        $agent = \think\facade\Request::header('user-agent');
        if (strpos($agent, 'MicroMessenger') !== false) {
            $payType = self::WX;
        } elseif (strpos($agent, 'AlipayClient') !== false) {
            //支付宝
            $payType = self::ZFB;
        } else {
//            $payType = 'Wx';
            throw new ApiException('请使用微信或支付宝支付');
        }
        return $payType;
    }

    /**---------------------二维码付款功能开始 【无需登录】---------------------**/
    //【白话，支付时，支付宝直接将买卖双方数据修改，支付宝app就会及时收到消息。异步不及时无所谓！】
    /**
     * 1.显示支付页面
     * @param Request $request
     * @return string
     */
    public function cashier(Request $request)
    {
        $payType = $this->getPayType();
        //1.通过卡牌找到对应的店铺名称

        $res = (new WeChatMerchantRepository())->getField($request['id'],'sub_mchid, store_name');
        if(empty($res)){
            return View::fetch('err', ['msg' => '商户并不存在']);
        }
        if(empty($res['sub_mchid'])){
            return View::fetch('err', ['msg' => '商户不支持']);
        }
        /**关键：获取用户的授权code，然后拿code去创建订单号**/
        $objName = '\\app\\service\\' . $payType . 'Service';
        if (!class_exists($objName)) {
            return View::fetch('err', ['msg' => '系统不支持该支付方式']);
        }
        $service = new $objName();
        $authCode = $service->getCode();
        //获取code
        $res['auth_code'] = $authCode;
        $sessionId = md5((string)$request->server('REQUEST_TIME_FLOAT')); //session_id，里面存储的是店铺id，user_id等信息
        View::assign([
            'shopName' => $res['store_name'],
            'sid' => $sessionId
        ]);
        session($sessionId, $res);
        return View::fetch(strtolower($payType));
    }


    /**
     * 2.用户扫收款码给商户付钱--被动
     * @param Request $request
     * @return \think\Response|void
     * @throws ApiException
     */
    public function qrpay(Request $request)
    {

        $price = $request['price'];
        if (empty($price) || 0 == preg_match('/(^[1-9]\d*(\.\d{1,2})?$)|(^0(\.\d{1,2})?$)/', $price)) {
            return $this->error('请填写正确的金额');
        }
        $cache = session($request['sid']);
        if (empty($cache)) {
            return $this->error('缺少必要参数');
        } elseif (empty($cache['auth_code'])) {
            return $this->error('缺少必要参数auth_code');
        }

        $payType = $this->getPayType();

        $objName = '\\app\\service\\' . $payType . 'Service';
        if (!class_exists($objName)) {
            return $this->error('系统不支持该支付方式');
        }
        $service = new $objName();

        $info['price'] = number_format(floatval($price), 2, '.', '');
        $info['remark'] = $request['remark'];
        //1.取消了支付后且订单金额没有改变，再次支付直接返回支付宝订单号或微信订单号；
        if (isset($cache['trade_no']) && $info['price'] == $cache['price']) {
            if ($cache['remark'] != $info['remark']) {
                //1.1取消订单后，只修改了备注，需要修改数据库订单信息
                $info['trade_no'] = $cache['trade_no'];
                $info['add_time'] = time();
                $result = $this->saveOrder($info, 'up');
                if (0 == $result) {
                    return $this->error('订单修改失败');
                }
            }
            return $this->success(['trade_no' => $cache['trade_no']]);
        }

        //是否已经获取买家id；
        if (empty($cache['buyerId'])) {
            $buyer = $service->getBuyerId($cache['auth_code']);
            if (0 == $buyer['code']) {
                return $this->error($buyer['msg'] . ' 缺少买家信息');
            }
            $cache['buyerId'] = $buyer['buyerId'];
        }


        //微信服务商用的sub_mchid来支付的,支付宝使用是auth_token
        switch ($payType) {
            case self::WX:
                $info['seller_id'] = $cache['sub_mchid'];   //商家id；
                break;
            case self::ZFB:

                break;
        }
        $info['buyerId'] = $cache['buyerId'];
        $info['order_no'] = orderNo();
        $info['shop_name'] = $cache['store_name'];
        //$order['trade_no']这里已经获取到微信和支付宝的订单号
        $order = $service->qrpayOrder($info);

        //4.修改session信息
        $cache['trade_no'] = $order['trace_id'];
        $cache['price'] = $info['price'];
        $cache['remark'] = $info['remark'];

        session($request['sid'], $cache);
        //新增订单信息
        $info['trade_no'] = $order['trace_id'];
        $this->saveOrder($info);
        return $this->success($order['result'], 'success');
    }


    /**
     * 增加或修改订单信息
     */
    private function saveOrder($data, $method = 'add')
    {
        $order = Order::getInstance();
        if ('add' == $method) {
            //新增
            $rs = $order->add($data);
        } elseif ('up' == $method) {
            //修改
            $rs = $order->up($data, ['order_no' => $data['order_no']], ['remark', 'trade_no','status','up_time']);
        }

        if (empty($rs)) {
            return 0;
        }
        return 1;
    }


    /**---------------------支付异步回调开始---------------------**/
    /**
     * 异步回调
     * @param Request $request
     * @return Request
     * @throws BaseException
     */
    public function notify(Request $request)
    {
        $body = file_get_contents("php://input");
        Log::channel('notify')->write($body);
        Log::channel('notify')->write(getallheaders());//获取header

        //微信v3异步返回的是json
        $arr = json_decode($body, true);
        if (!is_array($arr)) {
            //支付宝是key,val字符串
            parse_str($body, $arr);
        }
        if (isset($arr['trade_status'])) {
            /**支付宝回调，返回给支付宝的应答是字符串**/
//            if ('TRADE_SUCCESS' == $arr['trade_status'] || 'TRADE_FINISHED' == $arr['trade_status']) {
//                //支付宝支付成功
//                //1.验签
//                $server = new ZfbService();
//                $result = $server->check($arr);
//                if (false == $result) {
//                    echo 'fail,签名错误';
//                    exit; //直接退出，避免后续中间件输出json；支付宝无法获取
//                }
//                //2.更新数据库
//                $record = $this->up(self::ZFB, $arr);
//                if ($record) {
//                    echo "success";
//                    exit; //直接退出，避免后续中间件输出json；支付宝无法获取
//                }
//            }
        } elseif (isset($arr['resource']) && isset($arr['event_type'])) {
            /**微信回调，应答是json**/
            if ('TRANSACTION.SUCCESS' == $arr['event_type']) {
                $headers  = [
                    'Wechatpay-Signature' =>$request->header('Wechatpay-Signature'),
                    'Wechatpay-Timestamp' => $request->header('Wechatpay-Timestamp'),
                    'Wechatpay-Nonce' => $request->header('Wechatpay-Nonce'),
                    'Wechatpay-Serial' => $request->header('Wechatpay-Serial')
                ];

                //var_dump($request->header('Wechatpay-Signature'));

                //2.签名验证
                $server = new WxService();
                $res = $server->handleCallback($headers, $body);
                if (1 == $res['code']) {
                    //3.更新数据库
                    $record = $this->up(self::WX, $res['data']['decrypted_data']);
                    if ($record) {
//                        $request->responseStatus = 'SUCCESS';
//                        $request->responseMessage = '成功';
//                        return $request;
                          exit('SUCCESS');
                    }
                }
                exit('ERROR');
            }
        }
    }

    /**
     * 更新订单信息
     */
    private function up($type, $arr)
    {
        //判断该笔订单是否在商户网站中已经做过处理
        $order = Order::getInstance();

        $where['order_no'] = $arr['out_trade_no'];   //既是更新条件，又是验证条件；验证通知数据中的 out_trade_no 是否为商户系统中创建的订单号
        if (self::ZFB == $type) {
//            $where['trade_no'] = $arr['trade_no'];
//            $where['price'] = $arr['total_amount'];   //既是更新条件，又是验证条件；验证 total_amount 是否确实为该订单的实际金额
//            $where['seller_id'] = $arr['seller_id'];    //校验通知中的 seller_id（或者seller_email) 是否为 out_trade_no 这笔单据的对应的操作方
//            $allowField = ['status', 'up_time'];
        } elseif (self::WX == $type) {
            //$where['price'] = bcdiv($arr['amount']['total'], '100');  //既是更新条件，又是验证条件；验证total是否确实为该订单的实际金额,
            //$where['seller_id'] = $arr['sub_mchid'];    //校验通知中的 seller_id 是否为 out_trade_no 这笔单据的对应的操作方
            $allowField = ['status', 'up_time', 'trade_no'];
            $allowData['trade_no'] = $arr['transaction_id'];  //微信支付成功后，才返回微信订单号，prepay_id只是预支付标识。
        } else {
            return false;
        }

        $where['status'] = ORDER_WAIT;          //更新条件，判断该笔订单是否在商户网站中已经做过处理
        $info = $order->info($where, 'id');
        if (empty($info)) {
            return true;  //订单不存在，认为订单已经处理过，避免微信或支付宝再次发通知
        }
        if ($info) {
            $allowData['status'] = ORDER_SUC;
            $allowData['up_time'] = time();
            $res = $order->up($allowData, $where, $allowField);
            return true;
        }
    }
}